<?php
/**
 * Created by 784855684@qq.com.
 * Link: https://github.com/lichtung/inframe
 * User: linzh
 * Date: 6/25/17
 * Time: 5:46 PM
 */



namespace inframe\core;

use Workerman\Lib\Timer;
use  Workerman\Worker;

/**
 * Class Servant 服务框架
 * @package inframe\core
 */
class Servant
{
    /**
     * 初始化运行框架
     */
    public static function init()
    {
        static $_inited = false;
        if ($_inited) {
            return;
        }
        if (!IN_IS_CLI) die('Please use in client mode');
        if (IN_IS_WIN) {
            /**
             * 错误：multi workers init in one php file are not support
             * 由于windows下的php没有完善的进程控制接口，导致windows版本无法在一个启动脚本中实例化多个容器(Worker\WebServer\Gateway\BusinessWorker)进程。解决方法是使用多个启动脚本，每个脚本启动实例化一个容器，或者说每个端口一个启动文件。
             * 假设初始化两个Worker实例（tcp和websocket）和一个WebServer实例，则需要创建三个启动文件 start_socket_server.php 和 start_websocket_server.php start_webserver.php
             */
            require_once __DIR__ . '/../vendor/workerman/workerman-for-win/Autoloader.php';
            $gateway_dir = __DIR__ . '/../vendor/workerman/gateway-worker-for-win/src/';
            $socketio_dir = __DIR__ . '/../vendor/workerman/phpsocket.io-for-win/src/';
        } else {
            // 检查扩展
            if (!extension_loaded('pcntl')) exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n");

            if (!extension_loaded('posix')) exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
            require_once __DIR__ . '/../vendor/workerman/workerman/Autoloader.php';
            $gateway_dir = __DIR__ . '/../vendor/workerman/gateway-worker/src/';
            $socketio_dir = __DIR__ . '/../vendor/workerman/phpsocket.io/src/';
        }

        spl_autoload_register(function ($classname) use ($gateway_dir, $socketio_dir) {
            if (strpos($classname, 'GatewayWorker') === 0) {
                $file = $gateway_dir . str_replace('\\', '/', substr($classname, 14)) . '.php';
                is_file($file) and require($file);
            } elseif (strpos($classname, 'PHPSocketIO') === 0) {
                $file = $socketio_dir . str_replace('\\', '/', substr($classname, 12)) . '.php';
                is_file($file) and require($file);
            }
        });

        defined('SERVICE_NAME') or define('SERVICE_NAME', 'service' . IN_NOW);
        # 运行根目录
        $rootpath = IN_PATH_RUNTIME . SERVICE_NAME;
        Storage::mkdir($rootpath);

        Autoloader::setRootPath($rootpath);
        $_inited = true;
    }

    /**
     * 设置定时回调
     * @param callable $callable
     * @param int $interval
     */
    public static function setTimeout(callable $callable,$interval = IN_ONE_HOUR)
    {
        $task = new Worker();
        // 开启多少个进程运行定时任务，注意业务是否在多进程有并发问题
        $task->count = 1;
        $task->onWorkerStart = function ($task) use ($callable, $interval) {
            Timer::add($interval, function () use ($task, $callable) {
                try {
                    $callable($task);
                } catch (Throwable $t) {
                    echo $t->getMessage();
                }
            });
        };
    }

    /**
     * 开始所有进程
     */
    public static function start()
    {
        Worker::runAll();
    }


    /**
     * This will execute $cmd in the background (no cmd window) without
     * PHP waiting for it to finish, on both Windows and Unix.
     * @param string $cmd
     * @param callable|null $callback
     * @return void
     */
    public static function exec($cmd, callable $callback = null)
    {
        if (IN_IS_WIN) {
            pclose(popen("start /B {$cmd}", 'r'));
            sleep(1);//sleep(1);//延时一秒钟等待self::execInBackground($cmd)开始执行,避免过早进入$callback
        } else {
            exec("{$cmd} > /dev/null &");
        }
        $callback and $callback();
    }

}

Servant::init();